/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.aco.party.web.controller.system;

import com.aco.party.model.po.User;
import com.aco.party.model.vo.DataAnalyzeVo;
import com.aco.party.model.vo.UserQueryParam;
import com.aco.party.model.vo.UserRoleVo;
import com.aco.party.model.vo.common.Response;
import com.aco.party.model.vo.common.UserWithRoleVo;
import com.aco.party.security.token.OpenIdAuthenticationToken;
import com.aco.party.service.system.UserService;
import com.aco.party.util.CheckMobileUtil;
import com.aco.party.util.DateUtil;
import com.aco.party.util.MailUtil;
import com.aco.party.web.command.system.EditProfileCommand;
import com.aco.party.web.command.system.LoginCommand;
import com.aco.party.web.command.system.SignupCommand;
import com.aco.party.web.validator.system.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.context.annotation.Scope;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import static com.aco.party.util.WebModelUtil.getBasePath;

/**
 * Web MVC controller that handles security-related web requests, such as login and logout.
 */
@Scope("session")  //支持5种不同的作用域：singleton,prototype,request,session,global-session
@Controller
public class SecurityController extends BaseController {
    private Logger logger = Logger.getLogger(getClass().getName());
    @Resource
    private UserService userService;
    @Resource
    private TaskExecutor taskExecutor;

    private LoginValidator loginValidator = new LoginValidator();
    private EditPasswordValidator passwordValidator = new EditPasswordValidator();
    private SignupValidator signupValidator = new SignupValidator();
    private EditForgetPwdValidator forgetPwdValidator = new EditForgetPwdValidator();

    @RequestMapping(value="/system/home",method= RequestMethod.GET)
    public String systemHome(Model model) {
        DataAnalyzeVo vo = new DataAnalyzeVo();
        String today = DateUtil.dateToString(new Date(), "yyyyMMdd");
        String yesterday = DateUtil.dateToString(DateUtil.addDay(new Date(), -1),"yyyyMMdd");
        int todayCounts = userService.getCountByParam(today);
        int yesterdayCounts = userService.getCountByParam(yesterday);
        int totalCounts = userService.getUserCount();
        vo.setTodayNewUsers(todayCounts);
        vo.setYesterdayNewUsers(yesterdayCounts);
        vo.setTotalUsers(totalCounts);

        model.addAttribute("vo",vo);
        return "/system/home";
    }

    @RequestMapping(value="/login",method= RequestMethod.GET)
    public String showLoginForm(Model model, @ModelAttribute LoginCommand command) {
        return "client/login";
    }

    @RequestMapping(value="/login",method= RequestMethod.POST)
    public String login(HttpServletRequest request,Model model, @ModelAttribute LoginCommand command, BindingResult errors) {
        loginValidator.validate(command, errors);

        if( errors.hasErrors() ) {
            return showLoginForm(model, command);
        }
        System.out.println("command:"+command.getUsername()+","+command.getPassword());
        UsernamePasswordToken token = new UsernamePasswordToken(command.getUsername(), command.getPassword(), command.isRememberMe());
        try {
            SecurityUtils.getSubject().login(token);
            
        } catch (AuthenticationException e) {
            errors.reject( "error.login.generic", "用户名或者密码错误，请重新输入。" );
        }
        
        if( errors.hasErrors() ) {
            return showLoginForm(model, command);
        } else {
            String redirectUrl = "/system/home";
            if(!StringUtils.isEmpty(command.getRedirect_url())){
                redirectUrl = command.getRedirect_url();
            }
            //普通用户跳转到网站首页
            if(getCurrentUser().getId() != -1){
                UserWithRoleVo vo = userService.getUserWithRole(getCurrentUser().getId());
                if(vo != null){
                    if(vo.getRoleId() == 1 || vo.getRoleId() == 2 || vo.getRoleId() == 3){
                        return "redirect:/home";
                    }
                }
            }
            //手机端登录 也跳转到网站首页
            String userAgent = request.getHeader( "USER-AGENT" ).toLowerCase();

            boolean isFromMobile = CheckMobileUtil.check(userAgent);
            //判断是否为移动端访问
            if(isFromMobile){
                logger.info("移动端访问");
                return "redirect:/home";
            }
            return "redirect:" + redirectUrl;
        }
    }

    @ResponseBody
    @RequestMapping(value="/system/modifyName",method= RequestMethod.POST)
    public Response modifyName(Model model,@ModelAttribute EditProfileCommand command){
        User user = new User();
        user.setId(getCurrentUser().getId());
        user.setNickName(command.getName());
        userService.updateUser(user);
    	return new Response();
    }

    @ResponseBody
    @RequestMapping(value="/system/modifyWhois",method= RequestMethod.POST)
    public Response modifyWhois(Model model,@ModelAttribute EditProfileCommand command){
        User user = new User();
        user.setId(getCurrentUser().getId());
        user.setWhois(command.getWhoIs());
        userService.updateUser(user);
        return new Response();
    }

    @ResponseBody
    @RequestMapping(value="/system/modifypwd",method= RequestMethod.POST)
    public Response modifyPwd(Model model, EditProfileCommand command) {
        Response response = new Response();
    	User currentUser = getCurrentUser();
        if(StringUtils.isEmpty(command.getOldPwd())){
            response.setStatus(-1);
            response.setMsg("请输入原密码！");
            return response;
        }
        if(StringUtils.isEmpty(command.getNewPwd())){
            response.setStatus(-1);
            response.setMsg("请输入新密码！");
            return response;
        }
        if(StringUtils.isEmpty(command.getConPwd())){
            response.setStatus(-1);
            response.setMsg("请输入确认密码！");
            return response;
        }
        if(!command.getNewPwd().equals(command.getConPwd())){
            response.setStatus(-1);
            response.setMsg("新密码和确认密码不一致！");
            return response;
        }

        if(!currentUser.getPassword().equals(new Sha256Hash(command.getOldPwd()).toHex())){
            response.setStatus(-1);
            response.setMsg("原密码输入不正确！");
            return response;
        }
        User user = new User();
        user.setId(currentUser.getId());
        user.setPassword(new Sha256Hash(command.getNewPwd()).toHex());
        userService.updateUser(user);
        SecurityUtils.getSubject().logout();
    	return response;
    }
    

    @RequestMapping("/logout")
    public String logout() {
        SecurityUtils.getSubject().logout();
        return "redirect:/login";
    }

    @RequestMapping(value="/signup",method= RequestMethod.GET)
    public String showSignupForm(Model model, @ModelAttribute SignupCommand command) {
        return "client/signup";
    }

    @RequestMapping(value="/signup",method= RequestMethod.POST)
    public String showSignupForm(Model model, @ModelAttribute SignupCommand command, BindingResult errors) {
        signupValidator.validate(command, errors);

        if( errors.hasErrors() ) {
            return "client/signup";
        }

        User user = new User();
        command.toPo(user);
        userService.createUser(user);

        //注册默认普通用户
        userService.increaseRoles(user.getId(),1L);
        // Login the newly created user
//        SecurityUtils.getSubject().login(new UsernamePasswordToken(command.getUsername(), command.getPassword()));

        return "redirect:/login";
    }

    @RequestMapping(value = "/forgetPwd",method = RequestMethod.GET)
    public String forgetPwd(@ModelAttribute()SignupCommand command){
        return "client/forget_input";
    }

    @RequestMapping(value = "/forgetPwd",method = RequestMethod.POST)
    public String forgetPwd(Model model,@ModelAttribute()SignupCommand command, BindingResult errors){
        forgetPwdValidator.validate(command,errors);
        if(errors.hasErrors()) return "client/forget_input";

        String uuid = UUID.randomUUID().toString();
        User user = userService.findUserByName(command.getUsername());
        if(user != null){
            String url = getBasePath()+
                    "/reset-pwd?email=" + user.getEmail() + "&key=" + uuid;
            final String content = String.format("请点击下面链接进行密码重置：<a href='%s'>%s</a>",url,url);
            final String email = command.getEmail();
            taskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    MailUtil.sendMail(email, "Morketing重置密码", content);
                }
            });
            model.addAttribute("email", user.getEmail());
            User temp = new User();
            temp.setId(user.getId());
            temp.setExtra3(uuid);
            logger.info("生成uuid:" + uuid);
            userService.updateUser(temp);
            return "client/send_mail";
        }else{
            return "client/forget_input";
        }

    }

    @RequestMapping(value = "/reset-pwd",method = RequestMethod.GET)
    public String resetPwd(Model model,String email,String key,@ModelAttribute SignupCommand command){
        UserQueryParam param = new UserQueryParam();
        param.setEmail(email);
        List<User> users = userService.getUsersByParam(param);
        if(users != null && users.size() > 0){
            if(!StringUtils.isEmpty(users.get(0).getExtra3()) && users.get(0).getExtra3().equals(key)){
                model.addAttribute("result","true");
                command.setUsername(users.get(0).getUsername());
                command.setEmail(users.get(0).getEmail());
                return "client/forget_confirm";
            }
        }
        model.addAttribute("result","false");
        return "client/forget_confirm";
    }

    @RequestMapping(value = "/reset-pwd",method = RequestMethod.POST)
    public String resetPwdPost(Model model,@ModelAttribute SignupCommand command, BindingResult errors){
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "error.password.empty", "请输入密码");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPwd", "error.confirmPwd.empty", "请输入确认密码");
        if(!command.getPassword().trim().equals(command.getConfirmPwd().trim())){
            errors.reject("password","密码和确认密码不一致！");
        }
        if(!errors.hasErrors()){
            User user = userService.findUserByName(command.getUsername());
            if(user != null) {
                User temp = new User();
                temp.setId(user.getId());
                temp.setPassword(new Sha256Hash(command.getPassword()).toHex());
                temp.setExtra3("");
                userService.updateUser(temp);
                model.addAttribute("msg",String.format("修改密码成功！请！<a href='%s'>重新登录</a>",getBasePath() + "/login"));
                return "client/success";
            }
        }
        return "client/forget_confirm";
    }

    @RequestMapping(value = "/addProfile",method = RequestMethod.GET)
    public String addProfile(Model model,@ModelAttribute SignupCommand command){
        return "client/add_profile";
    }

    @RequestMapping(value = "/addProfile",method = RequestMethod.POST)
    public String postAddProfile(Model model,@ModelAttribute SignupCommand command, BindingResult errors){
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "error.email.empty", "请输入邮箱");
        if( org.apache.shiro.util.StringUtils.hasText(command.getEmail()) && !Pattern.matches(EditUserValidator.SIMPLE_EMAIL_REGEX, command.getEmail().toUpperCase()) ) {
            errors.rejectValue( "email", "error.email.invalid", "请输入邮箱地址格式！" );
        }
        User user = userService.findUserByEmail(command.getEmail());
        if(user != null){
            errors.reject("email","该邮箱已经存在，请重新填写邮箱地址！");
        }
        if(!errors.hasErrors()) {
            user = new User();
            command.toPo(user);
            user.setUsername(command.getOpenId());
            user.setExtra4(command.getOpenId());
            userService.createUser(user);

            //注册默认普通用户
            userService.increaseRoles(user.getId(), 1L);

            OpenIdAuthenticationToken token = new OpenIdAuthenticationToken(user.getUsername(), user.getUsername(),user.getPassword());
            SecurityUtils.getSubject().login(token);
            return "redirect:/home";
        }

        return "client/add_profile";
    }

}
